package com.wf.demo.info.service;

import com.alibaba.fastjson.JSONObject;
import com.wf.demo.info.dao.DeviceDAO;
import com.wf.demo.info.pojo.Company;
import com.wf.demo.info.pojo.Device;
import com.wf.demo.info.pojo.Model;
import com.wf.demo.info.util.LocalDateTimeUtils;
import com.wf.demo.info.util.Page4Navigator;
import com.wf.demo.info.util.ParseUtil;
import com.wf.demo.info.util.StatisticalUtil;
import com.wf.demo.job.pojo.DeviceNumberChangeOfCompany;
import com.wf.demo.job.pojo.TimeOfDevice;
import com.wf.demo.job.service.DeviceNumberChangeOfCompanyService;
import com.wf.demo.job.service.TimeOfDeviceService;
import com.wf.demo.job.util.JsonSearch;
import lombok.extern.slf4j.Slf4j;
import org.hsqldb.lib.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.*;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
@Slf4j
@Service
public class DeviceService {
    @Autowired
    DeviceDAO deviceDAO;
    @Autowired
    CompanyService companyService;
    @Autowired
    TimeOfDeviceService timeOfDeviceService;
    @Autowired
    DeviceNumberChangeOfCompanyService deviceNumberChangeOfCompanyService;
    @Autowired
    AlarmService alarmService;

    //list设备，带页面信息的device page
    public Page4Navigator<Device> list(int cid, int start, int size, int navigatePages){
        Company c=companyService.get(cid);
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        Pageable pageable = new PageRequest(start, size, sort);
        Page pageFromJPA = deviceDAO.findByCompany(c,pageable);
        return new Page4Navigator<>(pageFromJPA,navigatePages);
    }
    //list所有在线设备，带页面信息的device page
    public Page4Navigator<Device> listOnline( int start, int size, int navigatePages){
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        Pageable pageable = new PageRequest(start, size, sort);
        Page pageFromJPA = deviceDAO.findByIsOnline(true,pageable);
        return new Page4Navigator<>(pageFromJPA,navigatePages);
    }

    //根据北斗卡号得到设备
    public Device getBybeidouId(Long beidouId){
        Device device=deviceDAO.findByBeidouId(beidouId);
        return  device;
    }
    //
    public Device get(Long id) {
        return deviceDAO.findOne(id);
    }
    public void add(Device bean){
        deviceDAO.save(bean);
        //添加新设备时，会创建一个公司设备的数量变化情况记录 +1
        DeviceNumberChangeOfCompany dncoc=new DeviceNumberChangeOfCompany();
        dncoc.setNumberChangeDevice(1);
        dncoc.setCsNumber(bean.getCsNumber());
        dncoc.setCompany(bean.getCompany());
        deviceNumberChangeOfCompanyService.add(dncoc);
    }
    public void delete(Long id) {
        Device bean=deviceDAO.findOne(id);
        //删除新设备时，会创建一个公司设备的数量变化情况记录 -1
        DeviceNumberChangeOfCompany dncoc=new DeviceNumberChangeOfCompany();
        dncoc.setNumberChangeDevice(-1);
        dncoc.setCsNumber(bean.getCsNumber());
        dncoc.setCompany(bean.getCompany());
        deviceNumberChangeOfCompanyService.add(dncoc);
        //完成删除
        deviceDAO.delete(id);

    }
    public void update(Device bean){
        deviceDAO.save(bean);
    }
    public int  isExist(String csNumber,long beidouId) {
        Device device1=deviceDAO.findByCsNumber(csNumber);
        Device device2=deviceDAO.findByBeidouId(beidouId);
        if(null != device1)
            return  1; //存在控制系统编号重复
        if(null !=device2)
            return 2; //存在北斗ID重复
        return 0;   //不存在重复
    }
    public int  isExist(Device bean) {
        long id =bean.getId();
        Device device=deviceDAO.findOne(id);

        String csNumber =bean.getCsNumber();
        long beidouId=bean.getBeidouId();
        Device device1=deviceDAO.findByCsNumber(csNumber);
        Device device2=deviceDAO.findByBeidouId(beidouId);

        //如果和原控制系统编号不同，经查找后存在才算重复
        if(null != device1  &&  !device.getCsNumber().equals(bean.getCsNumber()))
            return  1; //存在控制系统编号重复
        //如果和原北斗ID不同，经查找后存在才算重复
        if(null !=device2   &&   !device.getBeidouId().equals(bean.getBeidouId()))
            return 2; //存在北斗ID重复
        return 0;   //不存在重复
    }
    /**
     *功能描述  设备在线模块设置(只针对接收到数据的设备)
     * @author wf
     * @date 2019/12/12
     * @param device
     * @return void
     */
    public  void setOnlineAndTime(Device device){
        Long totalTime =device.getOnlineTime();
        Long intervalTime =0l;
        //先将设备置为在线状态,如果设备状态为离线，则不计算在线时间等，因为离线太久的话上一次在线时间可能是很久之前
        if (device.isOnline() == false)
            device.setOnline(true);
        else{
            //读取设备的lastTime
            if(device.getLastTime() == null){
                //不进行累加计算，写入now时间
                device.setLastTime(LocalDateTime.now());
            }
            else{//计算差值
                intervalTime=LocalDateTimeUtils.getMillSecondByLocalDateTime(LocalDateTime.now())
                        -LocalDateTimeUtils.getMillSecondByLocalDateTime(device.getLastTime());
                totalTime =intervalTime+ totalTime;
                /**新增对每月在线时间的计算**/
                //找到此月的记录
                TimeOfDevice timeOfDevice=timeOfDeviceService.getOneOfMonth(device);
                //如果找到,即不为空并且该条记录就在此月就计算数值，否则创建新的表
                if (null !=timeOfDevice && LocalDateTimeUtils.isInThisMonth(timeOfDevice.getCreatTime())){

                    timeOfDevice.setOnlineTimeOfMonth(timeOfDevice.getOnlineTimeOfMonth()+intervalTime);
                    timeOfDeviceService.update(timeOfDevice);
                    log.info("没有创建新的月在线登记");
                }
                else {
                    TimeOfDevice timeOfDeviceNew=new TimeOfDevice();
                    timeOfDeviceNew.setCreatTime(LocalDate.now()); //获取当天日期
                    timeOfDeviceNew.setDevice(device); //绑定设备
                    timeOfDeviceService.add(timeOfDeviceNew);
                    log.info("创建了新的月在线登记，设备id是"+device.getId());
                }
                /**新增对每月在线时间的计算**/
                device.setLastTime(LocalDateTime.now());
                device.setOnlineTime(totalTime);
            }

        }

        //存入数据库
        deviceDAO.save(device);
    }
    /**
     *功能描述   设备的服务时长，单位毫秒ms，等于当下时间-开始使用日期（对于报废设备等于报废时间scrap_time-开始使用日期）
     *          设备每次接收到数据时调用此方法更新一次。
     * @author wf
     * @date 2020/6/8
     * @param
     * @return void
     */
    public  void setServiceTime(Device device){

        Long serviceTime =0l;

        //得到设备的开始使用日期   2019 08 02
        LocalDate startTime=device.getStartDate();
        //得到开始使用日期的那天的开始时间 2019 08 02 00 00 00
        LocalDateTime minStartTime = startTime.atTime(LocalTime.MIN);

            //如果设备报废
        if(device.getStatus() == 0){
            //设备报废时间
            LocalDateTime scrapTime=device.getScrapTime();
           serviceTime=LocalDateTimeUtils.getMillSecondByLocalDateTime(scrapTime)
                    -LocalDateTimeUtils.getMillSecondByLocalDateTime(minStartTime);
        }
        else {
            serviceTime=LocalDateTimeUtils.getMillSecondByLocalDateTime(LocalDateTime.now())
                    -LocalDateTimeUtils.getMillSecondByLocalDateTime(minStartTime);
        }
        device.setServiceLife(serviceTime);
        deviceDAO.save(device);
    }

    /**
     *功能描述 设备在线状态监测模块（只针对在线的设备，如果设备在线，
     * 但xx分钟都未接收到数据，则视为离线）
     * @author wf
     * @date 2019/12/2
     * @param timeInterval (时间差值，单位分钟min)
     * @return void
     */
    public  void monitorIsOnline(int timeInterval){
        //得到所有在线的设备
        List<Device> devicesOnline= deviceDAO.findByIsOnline(true);
        for(Device device :devicesOnline){
            //读取lastTime的时间戳ms
            Long lastTime= LocalDateTimeUtils.getMillSecondByLocalDateTime(device.getLastTime());
            //得到当前时间的时间戳ms
            Long nowTime= LocalDateTimeUtils.getMillSecondByLocalDateTime(LocalDateTime.now());
            Long timeIntervalMs =(long) (timeInterval *1000 *60) ;
            //lastTime和当前时间nowTime值差值≥timeInterval分钟,则设备已经离线了
            if(nowTime-lastTime>=timeIntervalMs){
                device.setOnline(false);
                deviceDAO.save(device);
            }
        }
    }
    /***************统计功能***************/
    //得到某公司下设备的统计信息
    public StatisticalUtil getStatisticalInfo(Company company){
        StatisticalUtil  su=new StatisticalUtil();
        su.setTotalNum(deviceDAO.countByCompany(company));  //总数量
        su.setOnlineNum(deviceDAO.countByCompanyAndIsOnline(company,true)); //在线
        su.setAlarmNum(deviceDAO.countByCompanyAndStatusAndIsOnline(company,2,true)); //报警  且在线
        su.setNormalNum(deviceDAO.countByCompanyAndStatusAndIsOnline(company,1,true)); //正常 且在线
        return  su;
    }
    //得到某机型下设备的统计信息
    public StatisticalUtil getStatisticalInfo(Model model){
        StatisticalUtil  su=new StatisticalUtil();
        su.setTotalNum(deviceDAO.countByModel(model));  //总数量
        su.setOnlineNum(deviceDAO.countByModelAndIsOnline(model,true)); //在线
        su.setAlarmNum(deviceDAO.countByModelAndStatusAndIsOnline(model,2,true)); //报警
        su.setNormalNum(deviceDAO.countByModelAndStatusAndIsOnline(model,1,true)); //正常且在线
        return  su;
    }
    //得到所有设备的统计信息,用于实时监控的界面的四个框

    public StatisticalUtil getAllStatisticalInfo(){
        StatisticalUtil  su=new StatisticalUtil();
        long totalNum  =0;
        long onlineNum =0;
        long alarmNum  =0;
        long normalNum =0;
        long scrapNumber=0;
        long notScrapAndOfflineNum=0;
        List<Company> companies=companyService.list();
        for (Company company:companies){
            totalNum= totalNum+deviceDAO.countByCompany(company);//总数量
            onlineNum=onlineNum+deviceDAO.countByCompanyAndIsOnline(company,true);//在线
            alarmNum=alarmNum+deviceDAO.countByCompanyAndStatusAndIsOnline(company,2,true);//报警
            normalNum=normalNum+deviceDAO.countByCompanyAndStatusAndIsOnline(company,1,true); //正常 且在线
            scrapNumber=scrapNumber+deviceDAO.countByCompanyAndStatusAndIsOnline(company,0,false); //报废且不在线
            notScrapAndOfflineNum=notScrapAndOfflineNum+deviceDAO.countByCompanyAndIsOnline(company,false)
                     -deviceDAO.countByCompanyAndStatusAndIsOnline(company,0,false);  //不在线但没有报废
        }
        su.setTotalNum(totalNum);
        su.setOnlineNum(onlineNum);
        su.setNormalNum(normalNum);
        su.setAlarmNum(alarmNum);
        return su;
    }
    //得到搜索到的设备的统计信息,用于实时监控的界面的四个框
    public StatisticalUtil getSearchStatisticalInfo(List<Device> devices){
        StatisticalUtil  su=new StatisticalUtil();
        long totalNum  =devices.size();
        long onlineNum =0;
        long alarmNum  =0;
        long normalNum =0;
        for (Device device:devices){
            if(device.isOnline())
            onlineNum=onlineNum+1;//在线
            if(device.getStatus()==2 && device.isOnline())
                alarmNum=alarmNum+1;//报警且在线
            if(device.getStatus()==1 && device.isOnline())
                normalNum=normalNum+1;//正常且在线
        }
        su.setTotalNum(totalNum);
        su.setOnlineNum(onlineNum);
        su.setNormalNum(normalNum);
        su.setAlarmNum(alarmNum);
        return su;
    }
    /***************查询功能***************/
    /**
     *功能描述
     * @author wf
     * @date 2019/12/12
     * @param jsonSearch
     * @return java.util.List<com.wf.demo.info.pojo.Device>
     */
    public  List<Device> searchDevice(JsonSearch jsonSearch)  {
        String cs_NumberOrFactoryDate=jsonSearch.getCsNumberOrFactoryDate();
        String modelName =jsonSearch.getModelName();
        String companyName =jsonSearch.getCompanyName();
        String status=jsonSearch.getStatus();

        Sort sort = new Sort(Sort.Direction.DESC,"id");

        //使用Specification的匿名类
        Specification<Device> specification=new Specification<Device>() {
            @Override
            public Predicate toPredicate(Root<Device> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList=new ArrayList<Predicate>();  //predicate语句集合
                //对输入内容进行处理
                if(! StringUtil.isEmpty(cs_NumberOrFactoryDate)){
                    //输入内容为出厂日期年月日
                    if(ParseUtil.checkYearMonthDay(cs_NumberOrFactoryDate)){
                        try {
                            LocalDate factoryDate=ParseUtil.stirng2LocalDate(cs_NumberOrFactoryDate);
                            //出厂日期模糊查询
                            Path<LocalDate> fd=root.get("factoryDate");
                            Predicate predicateFd=cb.equal(fd,factoryDate);
                            predicateList.add(predicateFd);
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                    }//控制系统编号模糊查询
                    else predicateList.add(cb.like(root.get("csNumber"),"%"+cs_NumberOrFactoryDate+"%"));
                }
                //公司名称精确查询
                if(! StringUtil.isEmpty(companyName)){
                    predicateList.add(cb.equal(root.get("company").get("name"),companyName));
                }
                //机型名称精确查询
                if(! StringUtil.isEmpty(modelName)){
                    predicateList.add(cb.equal(root.get("model").get("modelName"),modelName));
                }
                //发动机状态查询
                if(! StringUtil.isEmpty(status)){
                    int statusInt=Integer.parseInt(status);
                    predicateList.add(cb.equal(root.get("status"),statusInt));
                }
                Predicate endPredicate = cb.and(predicateList.toArray(new Predicate[predicateList.size()]));
                return endPredicate  ;
            }
        };
        List<Device> devices=deviceDAO.findAll(specification,sort);
        return  devices;
    }
    /**
     *功能描述   在设备管理中的搜索功能实现，
     * @author wf
     * @date 2019/12/23
     * @param jsonSearch
     * @return java.util.List<com.wf.demo.info.pojo.Device>
     */

    public  Page4Navigator<Device> searchDevice2(JsonSearch jsonSearch,int start, int size, int navigatePages)  {
        String cs_Number=jsonSearch.getCsNumberOrFactoryDate();
        String modelName =jsonSearch.getModelName();
        String companyName =jsonSearch.getCompanyName();
        String factorydate =jsonSearch.getFactoryDate();
        String status=jsonSearch.getStatus();

        Sort sort = new Sort(Sort.Direction.DESC,"id");
        Pageable pageable = new PageRequest(start, size, sort);
        //使用Specification的匿名类
        Specification<Device> specification=new Specification<Device>() {
            @Override
            public Predicate toPredicate(Root<Device> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList=new ArrayList<Predicate>();  //predicate语句集合
                if(ParseUtil.checkYearMonthDay(factorydate)){
                    try {
                        LocalDate factoryDate=ParseUtil.stirng2LocalDate(factorydate);
                        //出厂日期模糊查询
                        Path<LocalDate> fd=root.get("factoryDate");
                        Predicate predicateFd=cb.equal(fd,factoryDate);
                        predicateList.add(predicateFd);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                //控制系统编号模糊查询
                if(! StringUtil.isEmpty(cs_Number)){
                    predicateList.add(cb.like(root.get("csNumber"),"%"+cs_Number+"%"));
                }
                //公司名称精确查询
                if(! StringUtil.isEmpty(companyName)){
                    predicateList.add(cb.equal(root.get("company").get("name"),companyName));
                }
                //机型名称精确查询
                if(! StringUtil.isEmpty(modelName)){
                    predicateList.add(cb.equal(root.get("model").get("modelName"),modelName));
                }
                //设备状态查询
                if(! StringUtil.isEmpty(status)){
                    int statusInt=Integer.parseInt(status);
                    predicateList.add(cb.equal(root.get("status"),statusInt));
                }
                Predicate endPredicate = cb.and(predicateList.toArray(new Predicate[predicateList.size()]));
                return endPredicate  ;
            }
        };
       Page<Device> pageFromJPA=deviceDAO.findAll(specification,pageable);
        return new  Page4Navigator<>(pageFromJPA, navigatePages);

    }
    //单点监控中设备的累计在线，报警等时间 单位毫秒
    public  Object getSingleDeviceTimeStatistical(Device device){
        //累计在线
        long  totalOnlineTime =device.getOnlineTime();
        //累计报警
        long totalAlarmTime =alarmService.calculateTime(device);
        //累计正常
        long totalNormalTime =totalOnlineTime-totalAlarmTime;
        Map<String,Object> singleDeviceTimeMap= new HashMap<>();
        singleDeviceTimeMap.put("totalOnlineTime",totalOnlineTime);
        singleDeviceTimeMap.put("totalAlarmTime",totalAlarmTime);
        singleDeviceTimeMap.put("totalNormalTime",totalNormalTime);
        return  singleDeviceTimeMap;
    }
    /**
     *功能描述  在设备管理中，统计报废设备的最大使用寿命，平均，最小
     * @author wf
     * @date 2019/12/18
     * @param
     * @return java.lang.Object
     */

    public Object getStatisticalScrapDevice(){
            //得到所有报废设备
            List<Device> scrapDevices =deviceDAO.findByStatus(0);
            //算出他们的使用寿命=报废时间-开始工作时间，并储存成hashmap的格式
            //平均使用寿命
           Long  averageServiceLife= 0l;
            HashMap<Long, Long> hashMap = new HashMap<>();
            for(Device device:scrapDevices){
                //设备的开始使用日期没有时间，先设置成当天的0分0秒,
                LocalDateTime startTime=LocalDateTime.of(device.getStartDate(),LocalTime.MIN);
            //报废时间不为空
            if(null !=device.getScrapTime()){
                long serviceLife=LocalDateTimeUtils.getMillSecondByLocalDateTime(device.getScrapTime())-
                        LocalDateTimeUtils.getMillSecondByLocalDateTime(startTime);
                //map里面储存的是设备id和使用寿命
                hashMap.put(device.getId(),serviceLife);
                averageServiceLife=averageServiceLife+serviceLife;
            }
         }
            //总寿命除以设备数量
            averageServiceLife=averageServiceLife/scrapDevices.size();

        //調用sortHashMap()排序并返回新的集合
        LinkedHashMap<Long,Long> sortHashMap = sortHashMap(hashMap);
        //得到有序map中的第一个
        long maxId=sortHashMap.entrySet().iterator().next().getKey();
        long maxValue=sortHashMap.entrySet().iterator().next().getValue();
        //得到最后一个
        long minId=ParseUtil.getTail(sortHashMap).getKey();
        long minValue=ParseUtil.getTail(sortHashMap).getValue();
        System.out.println(sortHashMap);

        LinkedHashMap<String,Object> obj = new LinkedHashMap<>();
        obj.put("平均寿命",averageServiceLife);
        obj.put("最小使用寿命",minValue);
        obj.put("使用寿命最小的报废设备编号",deviceDAO.getOne(minId).getCsNumber());
        obj.put("最大使用寿命",maxValue);
        obj.put("使用寿命最大的报废设备编号",deviceDAO.getOne(maxId).getCsNumber());
        return  obj ;

    }
    public static  LinkedHashMap<Long,Long> sortHashMap(HashMap<Long,Long> map){
        //從HashMap中恢復entry集合，得到全部的鍵值對集合
        Set<Map.Entry<Long,Long>> entey = map.entrySet();
        //將Set集合轉為List集合，為了實用工具類的排序方法
        List<Map.Entry<Long,Long>> list = new ArrayList<Map.Entry<Long,Long>>(entey);

        //使用Collections工具類對list進行排序
        Collections.sort(list, new Comparator<Map.Entry<Long,Long>>() {
            @Override
            public int compare(Map.Entry<Long,Long> o1, Map.Entry<Long,Long> o2) {
                //按照age倒敘排列
                return (int) (o2.getValue()-o1.getValue());
            }
        });
        //創建一個HashMap的子類LinkedHashMap集合
        LinkedHashMap<Long,Long> linkedHashMap = new LinkedHashMap<Long,Long>();
        //將list中的數據存入LinkedHashMap中
        for(Map.Entry<Long,Long> entry:list){
            linkedHashMap.put(entry.getKey(),entry.getValue());
        }
        return linkedHashMap;
    }

}
